package io.itit.ecp.admin.provide.helper;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import io.itit.ecp.admin.common.enums.IEarlyWarningEnums;
import io.itit.ecp.admin.common.enums.IEarlyWarningPushEnums;
import io.itit.ecp.admin.common.enums.IEarlyWarningThresholdEnums;
import io.itit.ecp.admin.common.enums.IEnergyTypeEnums;
import io.itit.ecp.admin.server.entity.*;
import io.itit.ecp.admin.server.entity.extend.EnergyDataExtEntity;
import io.itit.ecp.admin.server.service.*;
import io.itit.grass.common.server.dto.ParamDto;
import io.itit.grass.common.server.utils.ConvertUtils;
import io.itit.grass.scheduler.server.entity.TaskSchedulerEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * 预警处理辅助类
 */
@Slf4j
@Component
public class EarlyWarningHelper implements InitializingBean {

    @Resource
    private IEarlyWarningService earlyWarningService;

    @Resource
    private IEarlyWarningThresholdService earlyWarningThresholdService;

    @Resource
    private IEarlyWarningRecordService earlyWarningRecordService;

    @Resource
    private IEarlyWarningUserService earlyWarningUserService;

    @Resource
    private IEarlyWarningPushService earlyWarningPushService;

    @Resource
    private IEnergyDataService energyDataService;

    private static EarlyWarningHelper meterDeviceWarningHelper;

    public static EarlyWarningHelper i() {
        return meterDeviceWarningHelper;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        meterDeviceWarningHelper = this;
    }

    /**
     *  计量设备预警处理
     * @Param meterCondition 计量条件(1:按时计量,2:按日计量,3:按月计量)
     */
    @Transactional(rollbackFor = Exception.class)
    public String runDeviceWarningTask(IEarlyWarningEnums.MeterCondition meterCondition, TaskSchedulerEntity taskScheduler) {
        List<EarlyWarningEntity> warningList = getWarningList(meterCondition, IEarlyWarningEnums.WarningType.warningType1);
        if (CollectionUtils.isEmpty(warningList)) {
            return "无[" + meterCondition.desc + "]的设备计量预警设置数据！";
        }
        // 查询参数
        ParamDto dto = getDateTimeParamDto(meterCondition);
        for (EarlyWarningEntity warning : warningList) {
            if (checkIfNotNeedPush(meterCondition, warning)) {
                continue;
            }
            dto.add("meterDeviceId", warning.getMeterDeviceId());
            // 获取设备时间段的计量值
            EnergyDataExtEntity data = DataRangeHelper.i().approve(()->energyDataService.sumMeterValue(dto));
            // 对比预警阀值
            EarlyWarningThresholdEntity threshold = compareThresholdValue(warning.getId(), data.getMeterValue());
            // 未达到预警阀值
            if (threshold == null){
                continue;
            }
            // 推送
            pushWarning(warning, threshold, data);
        }
        return "设备计量预警定时任务执行完成!";
    }

    /**
     *  碳排放预警处理
     * @Param meterCondition 计量条件(1:按时计量,2:按日计量,3:按月计量)
     */
    @Transactional(rollbackFor = Exception.class)
    public String runCarbonEmissionTask(IEarlyWarningEnums.MeterCondition meterCondition, TaskSchedulerEntity taskScheduler) {
        List<EarlyWarningEntity> warningList = getWarningList(meterCondition, IEarlyWarningEnums.WarningType.warningType2);
        if (CollectionUtils.isEmpty(warningList)) {
            return "无[" + meterCondition.desc + "]的碳排放预警设置数据！";
        }

        // 查询参数
        ParamDto dto = getDateTimeParamDto(meterCondition);
        for (EarlyWarningEntity warning : warningList) {
            if (checkIfNotNeedPush(meterCondition, warning)) {
                continue;
            }
            dto.add("meterDeviceId", warning.getMeterDeviceId());
            // 获取设备时间段的碳排放
            EnergyDataExtEntity data = DataRangeHelper.i().approve(()->energyDataService.sumCarbonEmission(dto));
            EarlyWarningThresholdEntity threshold = compareThresholdValue(warning.getId(), data.getCarbonEmission());
            if (threshold == null){
                continue;
            }
            // 推送
            pushWarning(warning, threshold, data);
        }
        return "碳排放预警定时任务执行完成!";
    }

    public List<EarlyWarningEntity> getWarningList(IEarlyWarningEnums.MeterCondition meterCondition, IEarlyWarningEnums.WarningType warningType){
        String now = DateUtil.formatDateTime(new Date());
        try{

            List<EarlyWarningEntity> list = DataRangeHelper.i().approve(()->earlyWarningService.lambdaQuery()
                    .eq(EarlyWarningEntity::getMeterCondition, meterCondition.meterCondition)
                    .eq(EarlyWarningEntity::getWarningType, warningType.warningType)
                    .le(EarlyWarningEntity::getStartTime, now)
                    .ge(EarlyWarningEntity::getEndTime, now)
                    .list());
            return list;
        }catch (Exception e) {
            log.error("获取预警设置列表失败", e);
            return null;
        }
    }

    /**
     * 检查是否不需要推送了
     */
    public boolean checkIfNotNeedPush(IEarlyWarningEnums.MeterCondition meterCondition, EarlyWarningEntity warning) {
        // 计量条件=按时计量 并且 推送规则!=实时推送 的情况
        if (IEarlyWarningEnums.MeterCondition.meterCondition1.equals(meterCondition) &&
            !IEarlyWarningEnums.PushType.pushType1.pushType.equals(warning.getPushType()))
        {
            // 已推送次数
            Integer pushCount = DataRangeHelper.i().approve(()->earlyWarningRecordService.countRecords(warning.getId(), null));
            // 限制推送的次数
            Integer numOfTimes = Integer.parseInt(warning.getPushType()) - 1;
            // 如果已经达到推送次数 就不需要推送了
            return pushCount >= numOfTimes;
        }
        // 按日和按月都是实时推送
        return false;
    }

    /**
     * 获取时间段查询参数
     * @param meterCondition  计量条件(1:按时计量,2:按日计量,3:按月计量)
     * @return ParamDto 带上时间范围的查询参数
     */
    public ParamDto getDateTimeParamDto(IEarlyWarningEnums.MeterCondition meterCondition) {
        // 获取前一个小时的时间段
        DateTime curDateTime = DateUtil.date();
        DateTime prevDateTime, solidifyDateStart, solidifyDateEnd;
        if (meterCondition.equals(IEarlyWarningEnums.MeterCondition.meterCondition1)){
            // 上一个小时
            prevDateTime = DateUtil.offset(curDateTime, DateField.HOUR_OF_DAY, -1);
            solidifyDateStart = DateUtil.beginOfHour(prevDateTime);
            solidifyDateEnd = DateUtil.endOfHour(prevDateTime);
        }else if (meterCondition.equals(IEarlyWarningEnums.MeterCondition.meterCondition2)){
            // 前一天
            prevDateTime = DateUtil.offset(curDateTime, DateField.DAY_OF_MONTH, -1);
            solidifyDateStart = DateUtil.beginOfDay(prevDateTime);
            solidifyDateEnd = DateUtil.endOfDay(prevDateTime);
        }else {
            // 上个月
            prevDateTime = DateUtil.offset(curDateTime, DateField.MONTH, -1);
            solidifyDateStart = DateUtil.beginOfMonth(prevDateTime);
            solidifyDateEnd = DateUtil.endOfMonth(prevDateTime);
        }
        return new ParamDto()
            .add("solidifyDateStart", DateUtil.formatDateTime(solidifyDateStart))
            .add("solidifyDateEnd", DateUtil.formatDateTime(solidifyDateEnd));
    }

    /**
     * 获取预警阀值并对比
     */
    public EarlyWarningThresholdEntity compareThresholdValue(String earlyWarningId, BigDecimal value) {
        List<EarlyWarningThresholdEntity> thresholdList = DataRangeHelper.i().approve(()->earlyWarningThresholdService.getThresholds(earlyWarningId));
        for (EarlyWarningThresholdEntity threshold : thresholdList) {
            if (IEarlyWarningThresholdEnums.JudgeRule.judgeRule1.judgeRule.equals(threshold.getJudgeRule())){
                // 大于等于
                if (value.compareTo(threshold.getThresholdValue()) >= 0){
                    return threshold;
                }
            }else{
                // 小于等于
                if (threshold.getThresholdValue().compareTo(value) >= 0){
                    return threshold;
                }
            }
        }
        return null;
    }

    /**
     * 生成预警推送记录
     */
    @Transactional(rollbackFor = Exception.class)
    public void pushWarning(EarlyWarningEntity warning, EarlyWarningThresholdEntity threshold, EnergyDataExtEntity data) {
        List<EarlyWarningUserEntity> users = DataRangeHelper.i().approve(()->earlyWarningUserService.lambdaQuery()
                .eq(EarlyWarningUserEntity::getEarlyWarningId, warning.getId())
                .list());
        if (CollectionUtils.isEmpty(users)){
            return;
        }
        // 保存预警记录
        EarlyWarningRecordEntity record = ConvertUtils.convertIgnoreId(warning, EarlyWarningRecordEntity.class);
        record.setEarlyWarningId(warning.getId());
        if (IEarlyWarningEnums.WarningType.warningType1.warningType.equals(record.getWarningType())){
            record.setMeterValue(data.getMeterValue());
        }else{
            record.setMeterValue(data.getCarbonEmission());
        }
        record.setPushRule(warning.getPushType());
        record.setJudgeRule(threshold.getJudgeRule());
        record.setThresholdValue(threshold.getThresholdValue());
        record.setThresholdLevel(threshold.getThresholdLevel());
        record.setEnergyTypeId(data.getEnergyTypeId());
        String unit = IEnergyTypeEnums.Type.valueOf(data.getEnergyTypeId()).unit;
        record.setThresholdUnit(unit);
        record.setCreateTm(null);
        record.setModifyTm(null);
        if (!DataRangeHelper.i().approve(()->earlyWarningRecordService.save(record))) {
            log.error("保存预警推送记录失败，预警设置ID=[" + warning.getId() + "]");
            return;
        }
        // 保存推送目标
        List<EarlyWarningPushEntity> pushUsers = ConvertUtils.convert(users, EarlyWarningPushEntity.class);
        pushUsers.forEach(t-> {
            t.setId(null);
            t.setEarlyWarningRecordId(record.getId());
            t.setStatus(IEarlyWarningPushEnums.Status.status1.status);
        });
        if (!DataRangeHelper.i().approve(()->earlyWarningPushService.saveBatch(pushUsers))){
            log.error("保存预警推送目标失败，预警设置ID=[" + warning.getId() + "]， 预警记录ID=[" + record.getId() + "]");
            return;
        }
        // TODO 推送消息
        log.info("预警信息推送成功");
    }

}
